package com.ciwong.epaper.util;

import android.content.Context;

import com.alibaba.sdk.android.oss.ClientConfiguration;
import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback;
import com.alibaba.sdk.android.oss.common.OSSLog;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider;
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.alibaba.sdk.android.oss.model.ResumableUploadRequest;
import com.alibaba.sdk.android.oss.model.ResumableUploadResult;
import com.ciwong.epaper.application.EpaperConstant;
import com.ciwong.epaper.modules.me.util.UploadFileHelper;
import com.ciwong.libs.utils.CWLog;
import com.ciwong.libs.utils.CWSys;
import com.ciwong.mobilelib.utils.BaseConstants;
import com.ciwong.mobilelib.utils.BaseSystem;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 阿里云OSS管理器
 *
 * @author bin
 * @version ciwong v.1.0 ${date}
 * @since ciwong v.1.0
 */
public class ALiYunManager {

    public static final String ACCESS_URL = "https://ep.dzb.ciwong.com/";

    private static final String ENDPOINT = "https://oss-cn-shenzhen.aliyuncs.com";

    private static final String ACCESS_KEY_ID = "LTAI5tJBcac6YfqW8AWFRPre";

    private static final String ACCESS_KEY_SECRET = "0ayl6Czt0KJwskY6SxGIHqeinE0S7x";

    private static final String BUCKET = "epbank";

    private OSSClient oss;

    private static Context mContext;

    private static ALiYunManager instance;

    /**
     * 正在上传队列
     */
    public Map<String, OSSAsyncTask> asyncTasks = new HashMap<String, OSSAsyncTask>();

    /**
     * 通知列表
     */
    private List<ALiYunListener> listeners = new ArrayList<ALiYunListener>();

    /**
     * 私有构造函数
     */
    private ALiYunManager() {
        initALiYun();
    }

    /**
     * 获取唯一实例
     *
     * @return 唯一实例
     */
    public static ALiYunManager getInstance() {
        if (instance == null) {
            syncInit();
        }
        return instance;
    }

    /**
     * 获取唯一实例
     *
     * @return 唯一实例
     */
    public static ALiYunManager initInstance(Context context) {
        mContext = context;
        if (instance == null) {
            syncInit();
        }
        return instance;
    }

    /**
     * 实例化对象
     */
    private static synchronized void syncInit() {
        if (instance == null) {
            instance = new ALiYunManager();
        }
    }

    /**
     * 设置上下文对象
     *
     * @param context 上下文对象
     */
    public static void setContext(Context context) {
        mContext = context;
    }

    /**
     * 初始化阿里云OSS
     */
    private void initALiYun() {
        OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(
                ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        ClientConfiguration conf = new ClientConfiguration();
        conf.setConnectionTimeout(5 * 60 * 1000); // 连接超时，默认15秒
        conf.setSocketTimeout(5 * 60 * 1000); // socket超时，默认15秒
        conf.setMaxConcurrentRequest(5); // 最大并发请求数，默认5个
        conf.setMaxErrorRetry(2); // 失败后最大重试次数，默认2次
        OSSLog.enableLog();// 调用此方法开启日志。
        oss = new OSSClient(mContext, ENDPOINT, credentialProvider, conf);
    }

    public synchronized void addDKFile(final String uploadFilePath, String objectKey, final Object tag) {
        if (null == uploadFilePath) {
            return;
        }

        if (!new File(uploadFilePath).exists()) {
            notifyFailureListener(tag, UploadFileHelper.ERROR_CODE_FILE_EXISTS);
            return;
        }
        if (asyncTasks.size() > 0 && asyncTasks.containsKey(uploadFilePath)) {
            return;
        }

        // 构造上传请求
        final PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET, objectKey, uploadFilePath);
        // 异步上传时可以设置进度回调
        putObjectRequest.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
            @Override
            public void onProgress(PutObjectRequest request, long currentSize,
                                   long totalSize) {
                notifyProgressListener(tag, currentSize, totalSize);
            }
        });
        OSSAsyncTask asyncTask = oss.asyncPutObject(putObjectRequest,
                new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                    @Override
                    public void onSuccess(PutObjectRequest request,
                                          PutObjectResult result) {
                        asyncTasks.remove(request.getUploadFilePath());
                        notifySuccessListener(tag, ACCESS_URL + request.getObjectKey());
                    }

                    @Override
                    public void onFailure(PutObjectRequest request,
                                          ClientException clientExcepion,
                                          ServiceException serviceException) {
                        int errorCode = UploadFileHelper.ERROR_CODE_SOCKET_TIME_OUT;
                        // 请求异常
                        if (clientExcepion != null) {
                            // 本地异常如网络异常等
                            clientExcepion.printStackTrace();
                        }
                        if (serviceException != null) {
                            // 服务异常
                            CWLog.e("ErrorCode",
                                    serviceException.getErrorCode());
                            CWLog.e("RequestId",
                                    serviceException.getRequestId());
                            CWLog.e("HostId", serviceException.getHostId());
                            CWLog.e("RawMessage",
                                    serviceException.getRawMessage());
                            errorCode = serviceException.getStatusCode();
                        }
                        OSSAsyncTask asyncTask = asyncTasks.get(uploadFilePath);
                        if (asyncTask != null) {
                            if (!asyncTask.isCanceled()) {
                                asyncTask.cancel();
                            }
                        }
                        notifyFailureListener(tag, errorCode);
                    }
                });


        //异步请求  非断点续传
        asyncTasks.put(uploadFilePath, asyncTask);

    }


    /**
     * 单个上传MP3文件任务
     *
     * @param uploadFilePath 本地文件路径
     * @param tag            唯一标识
     */
    public synchronized void addMP3(final String uploadFilePath, final Object tag) {


        if (null == uploadFilePath) {
            return;
        }

        if (!new File(uploadFilePath).exists()) {
            notifyFailureListener(tag, UploadFileHelper.ERROR_CODE_FILE_EXISTS);
            return;
        }
        if (asyncTasks.containsKey(uploadFilePath)) {
            //cancel(uploadFilePath);
            return;
        }
        try {
            // 构造上传请求
            final PutObjectRequest put = new PutObjectRequest(BUCKET,
                    getMP3Key(uploadFilePath), uploadFilePath);
            // 异步上传时可以设置进度回调
            put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
                @Override
                public void onProgress(PutObjectRequest request, long currentSize,
                                       long totalSize) {
                    notifyProgressListener(tag, currentSize, totalSize);
                }
            });
            OSSAsyncTask asyncTask = oss.asyncPutObject(put,
                    new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                        @Override
                        public void onSuccess(PutObjectRequest request,
                                              PutObjectResult result) {
                            asyncTasks.remove(request.getUploadFilePath());
                            notifySuccessListener(tag, ACCESS_URL + request.getObjectKey());
                        }

                        @Override
                        public void onFailure(PutObjectRequest request,
                                              ClientException clientExcepion,
                                              ServiceException serviceException) {
                            int errorCode = UploadFileHelper.ERROR_CODE_SOCKET_TIME_OUT;
                            StringBuilder stringBuilder = new StringBuilder();
                            // 请求异常
                            if (clientExcepion != null) {
                                // 本地异常如网络异常等
                                clientExcepion.printStackTrace();
                                stringBuilder.append("clientExcepion=" + clientExcepion.getMessage() + "  ");
                            }
                            if (serviceException != null) {
                                // 服务异常
                                CWLog.e("ErrorCode",
                                        serviceException.getErrorCode());
                                CWLog.e("RequestId",
                                        serviceException.getRequestId());
                                CWLog.e("HostId", serviceException.getHostId());
                                CWLog.e("RawMessage",
                                        serviceException.getRawMessage());
                                errorCode = serviceException.getStatusCode();
                                stringBuilder.append("serviceException=" + serviceException.getMessage());

                            }
                            cancel(uploadFilePath);
                            FeedbackUtil.getInstance().addFeedbackLog(FeedbackUtil.FEEDBACK_TYPE_ALIYUN_SUBMIT_WORK_RESULT, stringBuilder.toString(), EpaperConstant.UPLOAD_STATE_FAIL + "  " + ACCESS_URL + request.getObjectKey());
                            notifyFailureListener(tag, errorCode);
                        }
                    });
            //异步请求  非断点续传
            asyncTasks.put(uploadFilePath, asyncTask);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public synchronized void addPic(final String uploadFilePath, final Object tag) {
        if (null == uploadFilePath) {
            return;
        }

        if (!new File(uploadFilePath).exists()) {
            notifyFailureListener(tag, UploadFileHelper.ERROR_CODE_FILE_EXISTS);
            return;
        }
        if (asyncTasks.size() > 0 && asyncTasks.containsKey(uploadFilePath)) {
            return;
        }


        // 构造上传请求
        final PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET,
                getPicKey(uploadFilePath), uploadFilePath);
        // 异步上传时可以设置进度回调
        putObjectRequest.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
            @Override
            public void onProgress(PutObjectRequest request, long currentSize,
                                   long totalSize) {
                notifyProgressListener(tag, currentSize, totalSize);
            }
        });
        OSSAsyncTask asyncTask = oss.asyncPutObject(putObjectRequest,
                new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                    @Override
                    public void onSuccess(PutObjectRequest request,
                                          PutObjectResult result) {
                        asyncTasks.remove(request.getUploadFilePath());
                        notifySuccessListener(tag, ACCESS_URL + request.getObjectKey());
                    }

                    @Override
                    public void onFailure(PutObjectRequest request,
                                          ClientException clientExcepion,
                                          ServiceException serviceException) {
                        int errorCode = UploadFileHelper.ERROR_CODE_SOCKET_TIME_OUT;
                        // 请求异常
                        if (clientExcepion != null) {
                            // 本地异常如网络异常等
                            clientExcepion.printStackTrace();
                        }
                        if (serviceException != null) {
                            // 服务异常
                            CWLog.e("ErrorCode",
                                    serviceException.getErrorCode());
                            CWLog.e("RequestId",
                                    serviceException.getRequestId());
                            CWLog.e("HostId", serviceException.getHostId());
                            CWLog.e("RawMessage",
                                    serviceException.getRawMessage());
                            errorCode = serviceException.getStatusCode();
                        }
                        cancel(uploadFilePath);
                        notifyFailureListener(tag, errorCode);
                    }
                });


        //异步请求  非断点续传
        asyncTasks.put(uploadFilePath, asyncTask);

    }

    public synchronized void addFile(final String uploadFilePath, String objectKey, final Object tag) {
        if (null == uploadFilePath) {
            return;
        }

        if (!new File(uploadFilePath).exists()) {
            notifyFailureListener(tag, UploadFileHelper.ERROR_CODE_FILE_EXISTS);
            return;
        }
        if (asyncTasks.size() > 0 && asyncTasks.containsKey(uploadFilePath)) {
            return;
        }


        // 构造上传请求
        final PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET, objectKey, uploadFilePath);
        // 异步上传时可以设置进度回调
        putObjectRequest.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {
            @Override
            public void onProgress(PutObjectRequest request, long currentSize,
                                   long totalSize) {
                notifyProgressListener(tag, currentSize, totalSize);
            }
        });
        OSSAsyncTask asyncTask = oss.asyncPutObject(putObjectRequest,
                new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
                    @Override
                    public void onSuccess(PutObjectRequest request,
                                          PutObjectResult result) {
                        asyncTasks.remove(request.getUploadFilePath());
                        notifySuccessListener(tag, ACCESS_URL + request.getObjectKey());
                    }

                    @Override
                    public void onFailure(PutObjectRequest request,
                                          ClientException clientExcepion,
                                          ServiceException serviceException) {
                        int errorCode = UploadFileHelper.ERROR_CODE_SOCKET_TIME_OUT;
                        // 请求异常
                        if (clientExcepion != null) {
                            // 本地异常如网络异常等
                            clientExcepion.printStackTrace();
                        }
                        if (serviceException != null) {
                            // 服务异常
                            CWLog.e("ErrorCode",
                                    serviceException.getErrorCode());
                            CWLog.e("RequestId",
                                    serviceException.getRequestId());
                            CWLog.e("HostId", serviceException.getHostId());
                            CWLog.e("RawMessage",
                                    serviceException.getRawMessage());
                            errorCode = serviceException.getStatusCode();
                        }
                        cancel(uploadFilePath);
                        notifyFailureListener(tag, errorCode);
                    }
                });


        //异步请求  非断点续传
        asyncTasks.put(uploadFilePath, asyncTask);

    }

    /**
     * 添加任务
     *
     * @param uploadFilePath 本地文件路径
     * @param tag            唯一标识
     */
    public synchronized void add(final String uploadFilePath, final Object tag) {
        if (null == uploadFilePath) {
            return;
        }

        if (!new File(uploadFilePath).exists()) {
            notifyFailureListener(tag, UploadFileHelper.ERROR_CODE_FILE_EXISTS);
            return;
        }
        if (asyncTasks.containsKey(uploadFilePath)) {
            return;
        }


        String recordDirectory = BaseSystem.getProjectFolderPath() + File.separator + "oss_record" + File.separator;
        File recordDir = new File(recordDirectory);
        if (!recordDir.exists()) {
            recordDir.mkdirs();
        }
        //断点续传请求
        final ResumableUploadRequest request = new ResumableUploadRequest(BUCKET,
                getKey(uploadFilePath), uploadFilePath, recordDirectory);

        // 设置上传过程回调
        request.setProgressCallback(new OSSProgressCallback<ResumableUploadRequest>() {
            @Override
            public void onProgress(ResumableUploadRequest request, long currentSize, long totalSize) {
                notifyProgressListener(tag, currentSize, totalSize);
            }
        });

        OSSAsyncTask resumableTask = oss.asyncResumableUpload(request, new OSSCompletedCallback<ResumableUploadRequest, ResumableUploadResult>() {
            @Override
            public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
                asyncTasks.remove(request.getUploadFilePath());
                notifySuccessListener(tag, ACCESS_URL + request.getObjectKey());
            }

            @Override
            public void onFailure(ResumableUploadRequest request, ClientException clientExcepion, ServiceException serviceException) {

                int errorCode = UploadFileHelper.ERROR_CODE_SOCKET_TIME_OUT;
                // 请求异常
                if (clientExcepion != null) {
                    // 本地异常如网络异常等
                    clientExcepion.printStackTrace();
                }
                String des = "";
                if (serviceException != null) {
                    errorCode = serviceException.getStatusCode();
                    des = "服务异常如网络异常等 断点续传 ErrorCode: " + String.valueOf(serviceException.getErrorCode()) +
                            "RequestId:" + String.valueOf(serviceException.getRequestId()) + "HostId:" + String.valueOf(serviceException.getHostId()) +
                            "RawMessage:" + String.valueOf(serviceException.getRawMessage());
                }
                cancel(uploadFilePath);
                notifyFailureListener(tag + des, errorCode);

            }
        });


        //异步请求  非断点续传
        //asyncTasks.put(uploadFilePath, asyncTask);
        //异步请求  断点续传
        asyncTasks.put(uploadFilePath, resumableTask);
    }

    /**
     * 取消指定任务
     *
     * @param key 上传文件KEY
     */
    public void cancel(String key) {
        OSSAsyncTask asyncTask = asyncTasks.get(key);
        if (asyncTask != null) {
            if (!asyncTask.isCanceled()) {
                asyncTask.cancel();
            }
            asyncTasks.remove(key);
        }
    }

    /**
     * 释放资源
     */
    public void release() {
        Iterator iterator = asyncTasks.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            OSSAsyncTask asyncTask = (OSSAsyncTask) entry.getValue();
            asyncTask.cancel();
        }
        asyncTasks.clear();
        asyncTasks = null;
        oss = null;
        instance = null;
    }

    /**
     * 注册监听
     *
     * @param listener
     */
    public void registerListener(ALiYunListener listener) {
        listeners.add(listener);
    }

    /**
     * 注销监听
     *
     * @param listener
     */
    public void unRegisterListener(ALiYunListener listener) {
        listeners.remove(listener);
    }

    /**
     * 通知进度
     *
     * @param tag
     * @param currentSize
     * @param totalSize
     */
    private void notifyProgressListener(Object tag, long currentSize,
                                        long totalSize) {
        CWLog.d("debug", "currentSize: " + currentSize + " totalSize: "
                + totalSize + " tag: " + String.valueOf(tag));
        for (ALiYunListener listener : listeners) {
            listener.onProgress(tag, currentSize, totalSize);
        }
    }

    /**
     * 通知成功
     *
     * @param tag
     * @param url
     */
    private void notifySuccessListener(Object tag, String url) {
        CWLog.d("debug", "upload success : " + String.valueOf(tag));
        for (ALiYunListener listener : listeners) {
            listener.onSuccess(tag, url);
        }
    }

    /**
     * 通知失败
     *
     * @param tag
     * @param errorCode
     */
    private void notifyFailureListener(Object tag, int errorCode) {

        for (ALiYunListener listener : listeners) {
            listener.onFailure(tag, errorCode);
        }
    }

    /**
     * 获取上传文件KEY
     *
     * @param uploadFilePath 上传文件路径
     * @return KEY
     */
    public String getKey(String uploadFilePath) {
        return "work/" + CWSys
                .getSharedLong(BaseConstants.SHARE_PRE_CURR_LOGIN_USER, 0) + "/"
                + new File(uploadFilePath).getName();
    }

    /**
     * 获取上传MP3 文件KEY
     *
     * @param uploadFilePath 上传文件路径
     * @return KEY
     */
    public String getMP3Key(String uploadFilePath) {
        return "work/followread/" + CWSys
                .getSharedLong(BaseConstants.SHARE_PRE_CURR_LOGIN_USER, 0) + "/"
                + new File(uploadFilePath).getName();
    }

    public String getPicKey(String uploadFilePath) {
        return "work/online_answer_pic/" + CWSys
                .getSharedLong(BaseConstants.SHARE_PRE_CURR_LOGIN_USER, 0) + "/"
                + new File(uploadFilePath).getName();
    }

    public String getDubKey(String uploadFilePath) {
        return "work/dubing/" + CWSys
                .getSharedLong(BaseConstants.SHARE_PRE_CURR_LOGIN_USER, 0) + "/"
                + new File(uploadFilePath).getName();
    }


    /**
     * @param uploadFilePath
     * @return
     */
    public String getDkworKey(String uploadFilePath) {
        return "work/dkwork/" + CWSys
                .getSharedLong(BaseConstants.SHARE_PRE_CURR_LOGIN_USER, 0) + "/"
                + new File(uploadFilePath).getName();
    }

    /**
     * 阿里云上传文件接口
     */
    public interface ALiYunListener {

        /**
         * 进度
         *
         * @param tag
         * @param currentSize
         * @param totalSize
         */
        void onProgress(Object tag, long currentSize, long totalSize);

        /**
         * 完成
         *
         * @param tag
         */
        void onSuccess(Object tag, String url);

        /**
         * 失败
         *
         * @param tag
         * @param errorCode
         */
        void onFailure(Object tag, int errorCode);
    }
}
